﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using Baik;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Baik.Interface.Execution;
using Baik.Interface.Expression;
using IUndefined = Baik.Interface.Execution.IUndefined;

namespace Tester
{
    [TestClass]
    public class ScopeTest
    {
        public BaikInstance Instance = new BaikInstance();

        //DeclarationScope - Function
        [TestMethod]
        public void Given_a_function_is_declared_inside_another_function_when_trying_to_access_a_variable_then_it_should_check_the_parent_functions_scope()
        {
            var rtn = Instance.Evaluate("(a) {b:a; return (){return b;}; }('hi')();");
            Assert.IsTrue(rtn is IString);
        }
        [TestMethod]
        public void Given_a_function_is_declared_inside_an_object_when_trying_to_access_a_variable_then_it_should_check_the_objects_scope()
        {
            var rtnobj = Instance.Evaluate("a:{b:'hi'; c:(){return b;}; };");
            Assert.IsTrue(rtnobj.Get("b") is IString);
            Assert.IsTrue(rtnobj.Get("c") is IFunction);
            var rtnfun = Instance.Evaluate("a.c;");
            Assert.IsTrue(rtnfun is IFunction);
            var rtnval = Instance.Evaluate("a.c();");
            Assert.IsTrue(rtnval is IString);
            Assert.IsTrue(rtnval == rtnobj.Get("b"));
        }
        //DeclarationScope - Object
        [TestMethod]
        public void Given_object_declared_inside_object_when_access_varible_then_check_the_enclosing_object_scope ()
        {
            var rtnobj = Instance.Evaluate("a:{b:'hi'; c:{}};");
            var rtnval = Instance.Evaluate("a.c.b;");
            Assert.IsTrue(rtnval is IString);
            Assert.IsTrue(rtnval == rtnobj.Get("b"));
        }
        //AttachedScopeFunction - Access
        [TestMethod]
        public void Given_attached_function_declared_outside_object_when_access_variable_then_check_the_objects_scope()
        {
            var rtnobj = Instance.Evaluate("a:{b:'hi';};");
            var rtnfun = Instance.Evaluate("a.c:(){return b};");
            Assert.IsTrue(rtnfun is IFunction);
            var rtnval = Instance.Evaluate("a.c();");
            Assert.IsTrue(rtnval is IString);
            Assert.IsTrue(rtnval == rtnobj.Get("b"));
        }

        //can not see sibling declaration scope
        [TestMethod]
        public void Given_variable_is_decalred_in_brother_when_access_variable_then_return_undefined()
        {
            var rtnobj = Instance.Evaluate("a:{b:(){c:true;return c;};d:(){return c;};}");
            var rtnval = Instance.Evaluate("a.d()");
            Assert.IsTrue(rtnval is IUndefined);
            
        }
        
        
        //can not see uncle declaration scope
        
        [TestMethod]
        public void Given_variable_is_decalred_in_uncle_when_access_variable_then_return_undefined()
        {
            var rtnobj = Instance.Evaluate("a:{b:{c:true;};d:{e:c;};}");
            var rtnval = Instance.Evaluate("a.d.e");
            Assert.IsTrue(rtnval is IUndefined);
        }
        
    }
}
